package controllers;

import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;

import notifiers.Notificador;

import models.Alimento;
import models.Comible;
import models.ComidaDieta;
import models.EstablecimientoAlimenticio;
import models.Nutri;
import models.Paciente;
import models.Plato;
import models.PorcionAlimento;
import models.Usuario;
import models.Visibilidad;
import play.db.Model;
import play.exceptions.TemplateNotFoundException;
import play.mvc.With;

import com.google.gson.JsonElement;
import com.google.gson.JsonParser;

import controllers.deadbolt.Deadbolt;
import controllers.deadbolt.Restrict;
import controllers.deadbolt.Restrictions;
import controllers.securesocial.SecureSocial;

@With({ SecureSocial.class, Deadbolt.class })
public class Platos extends CustomCRUD {

	private static final String PERFIL_NUTRICIONISTA = "NUTRI";
	private static final String PERFIL_ESTABLECIMIENTO_ALIMENTICIO = "ESTABLECIMIENTO_ALIMENTICIO";

	public static void show() throws Exception {
		ObjectType type = ObjectType.get(getControllerClass());
		notFoundIfNull(type);

		if(getUsuarioLogueado().isEstablecimientoAlimenticio())
			render(getControllerName() + "/showEstablecimientoAlimenticio.html", type);
		else
			render(getControllerName() + "/show.html", type);
		
	}

	@Restrictions({@Restrict(PERFIL_ESTABLECIMIENTO_ALIMENTICIO)})
	public static void editPlato(Long id) throws Exception {
		ObjectType type = ObjectType.get(getControllerClass());
		notFoundIfNull(type);
		Plato plato = Plato.findById(id);
		render(getControllerName() + "/editPlato.html", type, plato);
	}
	
	public static void newPlato() throws Exception {
		ObjectType type = ObjectType.get(getControllerClass());
		notFoundIfNull(type);
		
		render(getControllerName() + "/newPlato.html", type);
	}

	//TODO: prioridad baja: hacer los routes más genéricos (no de nutris exclusivamente)
	@Restrictions({@Restrict(PERFIL_NUTRICIONISTA), @Restrict(PERFIL_ESTABLECIMIENTO_ALIMENTICIO)})
	public static void newPlatoAction() throws Exception{

		JsonParser parser = new JsonParser();
		JsonElement data = parser.parse(params.all().get("body")[0]);

		String nombre = data.getAsJsonObject().get("nombre").getAsString();

		Plato plato = new Plato(nombre);
		plato.setFechaCreacion(new Date());
		plato.setAutor(getUsuarioLogueado());
		
		ComidaDieta comidaDieta = new ComidaDieta();
		comidaDieta.save();
		plato.setVisibilidad(Visibilidad.valueOf("NADIE"));
		
		Iterator<JsonElement> iterator = data.getAsJsonObject().get("alimentos").getAsJsonArray().iterator();
		while(iterator.hasNext()){
			JsonElement jsonElement = iterator.next();
			
			String idAlimentoStr = jsonElement.getAsJsonObject().get("idAlimento").getAsString();
			Long idAlimento = Long.parseLong(idAlimentoStr);
			Alimento alimento = Alimento.findById(idAlimento);
			String cantidadPorcionesStr = jsonElement.getAsJsonObject().get("cantidadPorciones").getAsString();
			Integer cantidadPorciones = Integer.parseInt(cantidadPorcionesStr);
			
			PorcionAlimento porcionAlimento = new PorcionAlimento(alimento, cantidadPorciones);
			
			plato.agregarPorcionAlimento(porcionAlimento);
		}
		
		plato.save();
		if(getUsuarioLogueado().isEstablecimientoAlimenticio()){
			renderJSON("{\"result\": \"establecimiento_alimenticio\"}");
		}
		renderJSON("{\"result\": \"nutri\"}");
	}

	//Guarda los cambios del plato que se edito en Resto
	@Restrictions({@Restrict(PERFIL_NUTRICIONISTA), @Restrict(PERFIL_ESTABLECIMIENTO_ALIMENTICIO)})
	public static void savePlatoAction(String platoId) throws Exception{
		
		JsonParser parser = new JsonParser();
		JsonElement data = parser.parse(params.all().get("body")[0]);
		
		String nombre = data.getAsJsonObject().get("nombre").getAsString();
		
		Plato platoDelete = Plato.findById(Long.parseLong(platoId));

		//Guardo la fecha de creación original
		Date fechaCreacion = (Date) platoDelete.getFechaCreacion().clone();
		
		platoDelete.delete();
		
		Plato plato = new Plato(nombre);
		plato.setFechaCreacion(fechaCreacion);
		plato.setAutor(getUsuarioLogueado());
		
		ComidaDieta comidaDieta = new ComidaDieta();
		comidaDieta.save();
		plato.setVisibilidad(Visibilidad.valueOf("NADIE"));
		
		Iterator<JsonElement> iterator = data.getAsJsonObject().get("alimentos").getAsJsonArray().iterator();
		while(iterator.hasNext()){
			JsonElement jsonElement = iterator.next();
			
			String idAlimentoStr = jsonElement.getAsJsonObject().get("idAlimento").getAsString();
			Long idAlimento = Long.parseLong(idAlimentoStr);
			Alimento alimento = Alimento.findById(idAlimento);
			String cantidadPorcionesStr = jsonElement.getAsJsonObject().get("cantidadPorciones").getAsString();
			Integer cantidadPorciones = Integer.parseInt(cantidadPorcionesStr);
			
			PorcionAlimento porcionAlimento = new PorcionAlimento(alimento, cantidadPorciones);
			
			plato.agregarPorcionAlimento(porcionAlimento);
		}
		
		plato.save();
		if(getUsuarioLogueado().isEstablecimientoAlimenticio()){
			renderJSON("{\"result\": \"establecimiento_alimenticio\"}");
		}
		renderJSON("{\"result\": \"nutri\"}");
	}
	
	@Restrictions({@Restrict(PERFIL_ESTABLECIMIENTO_ALIMENTICIO)})
	public static void eliminarPlatoAction() throws Exception{

		JsonParser parser = new JsonParser();
		JsonElement data = parser.parse(params.all().get("body")[0]);

		String idPlato = data.getAsJsonObject().get("idPlato").getAsString();
		
		Plato plato = Plato.findById(Long.parseLong(idPlato));
		plato.delete();
		
		if(getUsuarioLogueado().isEstablecimientoAlimenticio()){
			renderJSON("{\"result\": \"establecimiento_alimenticio\"}");
		}
		
		renderJSON("{\"result\": \"nutri\"}");
	}

	@Restrictions({@Restrict(PERFIL_ESTABLECIMIENTO_ALIMENTICIO)})
	public static String getNombre(String platoId) throws Exception{
		Plato plato = Plato.findById(Long.parseLong(platoId));
		return plato.getNombre();
	}

	@Restrictions({@Restrict(PERFIL_ESTABLECIMIENTO_ALIMENTICIO)})
	public static String getCaloriasPlato(String platoId) throws Exception{
		Plato plato = Plato.findById(Long.parseLong(platoId));
		return plato.calcularCalorias().toString();
	}
	
	@Restrictions({@Restrict(PERFIL_NUTRICIONISTA), @Restrict(PERFIL_ESTABLECIMIENTO_ALIMENTICIO)})
	public static void publicar(String id, String visibilidad) throws Exception{
		Plato plato = Plato.findById(Long.parseLong(id));
		plato.setVisibilidad(Visibilidad.valueOf(visibilidad));
		plato.save();
		show();
	}
	
	@Restrict(PERFIL_NUTRICIONISTA)
	public static String asignar(String json){
		
		JsonParser parser = new JsonParser();
		JsonElement data = parser.parse(params.all().get("body")[0]);

		List<Paciente> pacientes = new ArrayList<Paciente>();
		Iterator<JsonElement> pacientesIterator = data.getAsJsonObject().get("pacientes").getAsJsonArray().iterator();
		while(pacientesIterator.hasNext()){
			JsonElement jsonElement = pacientesIterator.next();
			String idPacienteStr = jsonElement.getAsJsonObject().get("idPaciente").getAsString();
			Long idPaciente = Long.parseLong(idPacienteStr);
			Paciente paciente = Paciente.findById(idPaciente);
			pacientes.add(paciente);
		}
		
		//En realidad es de un plato a varios pacientes la asignación, pero queda así por las dudas
		Iterator<JsonElement> platosIterator = data.getAsJsonObject().get("platos").getAsJsonArray().iterator();
		while(platosIterator.hasNext()){
			JsonElement platoJsonElement = platosIterator.next();
			String idPlatoStr = platoJsonElement.getAsJsonObject().get("idPlato").getAsString();
			Long idPlato = Long.parseLong(idPlatoStr);
			Plato plato = Plato.findById(idPlato);

			//TODO: ojo performance, no está bueno borrar todo y recrear todo
			List<Long> backupIdsPacientes = new ArrayList<Long>();
			
			for(Paciente p : plato.getPacientesAsignadosAEstePlato()){
				backupIdsPacientes.add(new Long(p.id));
			}
			
			resetearAsignacionesDePlato(plato);
			for(Paciente paciente : pacientes){
				paciente.getPlatosAsignadosAPaciente().add(plato);
				paciente.save();
				if(!backupIdsPacientes.contains(paciente.id)){
					Notificador.emailAsignarPlato(paciente, plato);
				}
			}
			plato.setPacientesAsignadosAEstePlato(pacientes);
			plato.save();
		}
		
		return "ok";
	}
	
	protected static void resetearAsignacionesDePlato(Plato plato) {
		//Cada vez que asigna pacientes, borra todos los actuales y deja la asignación tal como se seleccionó en la pantalla, todo con AJAX7
		//TODO: optimizar! ofCourse
		for(Paciente paciente : plato.getPacientesAsignadosAEstePlato()){
			paciente.getPlatos().remove(plato);
			paciente.save();
		}
		plato.getPacientesAsignadosAEstePlato().clear();
		plato.save();
	}

	@Restrict(PERFIL_NUTRICIONISTA)
	public static void deshabilitar(String id){
		
	}
	
	/**
	 * Retorna en formato Json los "alimentos" encontrados segun el nombre
	 */
	public static void buscarAlimento(String nombre) {
		List<Comible> alimentos = Alimento.findByNombre(nombre);
		renderJSON(alimentos);
	}
	
	@Restrict(PERFIL_NUTRICIONISTA)
	public static void list(int page, String search, String searchFields, String orderBy, String order) {

		Nutri nutri = (Nutri) getUsuarioLogueado();

		Long userId = nutri.id;

		ObjectType type = ObjectType.get(getControllerClass());
		notFoundIfNull(type);

		if (page < 1) {
			page = 1;
		}

		List<Plato> objects = nutri.getPlatos();

		Long count = new Long(objects.size());
		Long totalCount = new Long(objects.size());
		List<Paciente> pacientes = nutri.getPacientes();
		try {
			render(type, objects, count, totalCount, page, orderBy, order, userId, pacientes);
		} catch (TemplateNotFoundException e) {
			render(getControllerName() + "/list.html", type, objects, count, totalCount, page, orderBy, order, userId, pacientes);
		}
	}
	
	@Restrict(PERFIL_ESTABLECIMIENTO_ALIMENTICIO)
	public static void listEstablecimientosAlimenticios(int page, String search, String searchFields, String orderBy, String order) {

		EstablecimientoAlimenticio establecimientoAlimenticio = (EstablecimientoAlimenticio) getUsuarioLogueado();

		Long userId = establecimientoAlimenticio.id;

		ObjectType type = ObjectType.get(getControllerClass());
		notFoundIfNull(type);

		if (page < 1) {
			page = 1;
		}

		List<Plato> objects = establecimientoAlimenticio.getPlatos();

		Long count = new Long(objects.size());
		Long totalCount = new Long(objects.size());
		try {
			render(type, objects, count, totalCount, page, orderBy, order, userId);
		} catch (TemplateNotFoundException e) {
			render(getControllerName() + "/listEstablecimientosAlimenticios.html", type, objects, count, totalCount, page, orderBy, order, userId);
		}
	}

	public static void seleccionarPacientes(){
		ObjectType type = ObjectType.get(getControllerClass());
		notFoundIfNull(type);
		JsonParser parser = new JsonParser();
		JsonElement data = parser.parse(params.all().get("body")[0]);
		renderJSON(data);
	}
	
	public static void showAutorPlato() {
		JsonParser parser = new JsonParser();
		JsonElement data = parser.parse(params.all().get("body")[0]);
		Long idPlato = Long.parseLong(data.getAsJsonObject().get("idPlato").getAsString());
		Plato plato = Plato.findById(idPlato);
		String nombreAutor = plato.getAutor().getNombre();
		String emailAutor = plato.getAutor().getEmail();
		renderJSON("{\"result\": \"ok\", \"nombreAutor\": \"" + nombreAutor + "\", \"emailAutor\": \"" + emailAutor + "\"}");
	}

	public static String guardarPlatoIdEnSesion() {
		JsonParser parser = new JsonParser();
		JsonElement data = parser.parse(params.all().get("body")[0]);
		String platoId = data.getAsJsonObject().get("platoId").getAsString();
		session.put("plato_id", platoId);
		return "ok";
	}
	
	@Restrict(PERFIL_NUTRICIONISTA)
	public static String getPacientesJSON(String platoId) {
		
		Plato plato = Plato.findById(Long.parseLong(platoId));
		Usuario usuario = getUsuarioLogueado();
		List<Paciente> pacientesAsignados = plato.getPacientesAsignadosAEstePlato();
		List<Paciente> pacientesNutri = ((Nutri) usuario).getPacientes();
		
		if(pacientesNutri.isEmpty()){
			return null;
		}
		
		String json = "[";
		for (Paciente paciente : pacientesNutri) {
			if (pacientesAsignados.contains(paciente)) {
				json += "{\"pacienteId\":" + paciente.id + ",\"pacienteNombre\": \"" + paciente.getNombre() + "\",\"pacienteChecked\": true},";
			} else {
				json += "{\"pacienteId\":" + paciente.id + ",\"pacienteNombre\": \"" + paciente.getNombre() + "\",\"pacienteChecked\": false},";
			}
		}
		json = json.substring(0, json.length() - 1);
		json += "]";

		return json;
	}

}
